package it.omnisong.server.retrieval;

import it.omnisong.client.model.Link;
import it.omnisong.client.model.Song;
import it.omnisong.server.persistence.dao.LinkDAO;
import it.omnisong.server.persistence.dao.SongDAO;
import it.omnisong.server.persistence.postgres.PostgresException;

import java.io.IOException;
import java.net.MalformedURLException;
import java.sql.SQLException;
import java.util.List;

import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.ThreadedRefreshHandler;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

public abstract class AbstractDataSource implements Runnable {

	private String currentSongUrl;
	private String baseUrl;
	private String xPathAlbumQuery;
	private String xPathAuthorQuery;
	private String xPathLyricQuery;
	private String xPathTitleQuery;

	protected final int AS_TEXT = 1;
	protected final int AS_XML = 2;

	private WebClient webClient;

	public WebClient getWebClient() {
		return webClient;
	}

	public void setWebClient(WebClient webClient) {
		this.webClient = webClient;
	}

	public String getCurrentSongUrl() {
		return currentSongUrl;
	}

	public void setCurrentSongUrl(String currentSongUrl) {
		this.currentSongUrl = currentSongUrl;
	}

	public String getBaseUrl() {
		return baseUrl;
	}

	public void setBaseUrl(String baseUrl) {
		this.baseUrl = baseUrl;
	}

	public String getxPathAlbumQuery() {
		return xPathAlbumQuery;
	}

	public void setxPathAlbumQuery(String xPathAlbumQuery) {
		this.xPathAlbumQuery = xPathAlbumQuery;
	}

	public String getxPathAuthorQuery() {
		return xPathAuthorQuery;
	}

	public void setxPathAuthorQuery(String xPathAuthorQuery) {
		this.xPathAuthorQuery = xPathAuthorQuery;
	}

	public String getxPathLyricQuery() {
		return xPathLyricQuery;
	}

	public void setxPathLyricQuery(String xPathLyricQuery) {
		this.xPathLyricQuery = xPathLyricQuery;
	}

	public String getxPathTitleQuery() {
		return xPathTitleQuery;
	}

	public void setxPathTitleQuery(String xPathTitleQuery) {
		this.xPathTitleQuery = xPathTitleQuery;
	}

	public AbstractDataSource() {
		webClient = new WebClient();
		webClient.setJavaScriptEnabled(false);
		webClient.setRedirectEnabled(false);
		webClient.setRefreshHandler(new ThreadedRefreshHandler());
	}

	/**
	 * Fill Database with song lyrics and URLs
	 */
	public void fillDatabase(List<Link> links) {

		SongDAO songDAO = null;
		LinkDAO linkDAO = null;
		try {
			songDAO = new SongDAO();
			linkDAO = new LinkDAO();
		} catch (PostgresException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		for (Link webLink : links) {
			Song song = null;
			setCurrentSongUrl(getBaseUrl() + webLink.getUrl());
			/* Controllo se il link è già presente */
			List<Link> previousLinks = null;
			try {
				previousLinks = linkDAO.get(getBaseUrl() + webLink.getUrl());
			} catch (PostgresException ex) {
				System.out.println("LinkDAO.get --> error " + ex.getMessage());
			}
			if (previousLinks.size() == 0) {
				/* Controllo se la canzone è già presente */
				List<Song> previousSongs = null;
				try {
					previousSongs = songDAO.get(webLink.getSong().getTitle(), webLink.getSong().getArtist());
				} catch (PostgresException ex) {
					System.out.println("SongDAO.get --> error "
							+ ex.getMessage());
				}
				if (previousSongs.size() == 0) { // La canzone va aggiunta
					try {
						song = getSongMetaData(AS_TEXT);
					} catch (Exception ex) {
						System.out.println("getSongMetadata --> error " + ex.getMessage());
						continue;
					}
					Link link = new Link();
					link.setUrl(getBaseUrl() + webLink.getUrl());
					link.setRank(0);
					link.setSong(song);
					try {
						linkDAO.insertLink(link);
					} catch (PostgresException ex) {
						System.out.println("LinkDAO.insertLink --> error "
								+ ex.getMessage());
					}

					System.out.println("A new Link has been added: " + link);
					System.out.println("A new Song has been added: " + song);

				} else { // La canzone è presente: aggiungo solo il link

					Link link = new Link();
					link.setUrl(getBaseUrl() + webLink.getUrl());
					link.setRank(0);
					try {
						linkDAO.insertLink(link, previousSongs.get(0));
					} catch (PostgresException ex) {
						System.out.println("LinkDAO.insertLink --> error "
								+ ex.getMessage());
					}
					System.out.println("A new Link has been added: " + link);
				}
			}
		}
	}

	public void getSongMetaData() throws FailingHttpStatusCodeException,
			MalformedURLException, IOException {

		getSongMetaData(AS_TEXT);
	}

	public Song getSongMetaData(int retrieveMode)
			throws FailingHttpStatusCodeException, MalformedURLException,
			IOException {

		HtmlPage page = null;
		Song currentSong = new Song();
		page = webClient.getPage(getCurrentSongUrl());

		HtmlElement lyric = (HtmlElement) page.getByXPath(getxPathLyricQuery())
				.get(0);
		HtmlElement artist = (HtmlElement) page.getByXPath(
				getxPathAuthorQuery()).get(0);
		HtmlElement title = (HtmlElement) page.getByXPath(getxPathTitleQuery())
				.get(0);

		currentSong.setArtist(artist.asText());
		currentSong.setTitle(title.asText());

		if (retrieveMode == AS_TEXT) {
			currentSong.setLyric(lyric.asText());
		} else if (retrieveMode == AS_XML) {
			currentSong.setLyric(lyric.asXml());
		}
		return currentSong;
	}

	public abstract List<Link> collectLinksByLetter();

	public void run() {
		List<Link> allLinks = collectLinksByLetter();
		try {
			fillDatabase(allLinks);
		} catch (FailingHttpStatusCodeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally {

		}
	}
}
